package cn.lg.soar.system.auth.service.impl;

import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.database.base.service.impl.BaseServiceImpl;
import cn.lg.soar.system.auth.entity.DataRule;
import cn.lg.soar.system.auth.entity.DataRuleItem;
import cn.lg.soar.system.auth.entity.DataScope;
import cn.lg.soar.system.auth.mapper.DataRuleMapper;
import cn.lg.soar.system.auth.mapper.DataScopeMapper;
import cn.lg.soar.system.auth.model.DataRuleVO;
import cn.lg.soar.system.auth.service.IDataRuleItemService;
import cn.lg.soar.system.auth.service.IDataRuleService;
import cn.lg.soar.system.config.AuthCacheKey;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * DataRule服务层实现
 * 数据源
 * @author luguoxiang
 * @since 2022-04-30
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class DataRuleServiceImpl extends BaseServiceImpl<DataRuleMapper, DataRule> implements IDataRuleService {

    @Autowired
    private DataScopeMapper dataScopeMapper;
    @Autowired
    private IDataRuleItemService dataRuleItemService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeByIds(Collection<?> list) {
        if (DataUtil.isEmpty(list)) {
            return true;
        }
        List<DataRule> dataScopes = list(
                Wrappers.<DataRule>lambdaQuery()
                        .select(DataRule::getResourceId)
                        .in(DataRule::getId, list)
        );
        Cache cache = cacheManager.getCache(AuthCacheKey.RESOURCE_RULE_MAP);
        Assert.notNull(cache, "缓存不存在");
        // 逐条清理缓存
        for (DataRule dataRule : dataScopes) {
            cache.evict(dataRule.getResourceId());
        }

        super.removeByIds(list);
        List<Long> itemIds = dataRuleItemService.listObjs(
                Wrappers.<DataRuleItem>lambdaQuery()
                        .select(DataRuleItem::getId)
                        .in(DataRuleItem::getRuleId, list),
                x -> Long.parseLong(x.toString())
        );
        dataRuleItemService.removeByIds(itemIds);
        dataScopeMapper.delete(
                Wrappers.<DataScope>lambdaQuery()
                        .in(DataScope::getRuleId, list)
        );
        return true;
    }

    @CacheEvict(value = AuthCacheKey.RESOURCE_RULE_MAP, key = "#data.resourceId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Serializable create(DataRuleVO data) {
        handleDefaulted(data);
        AssertUtil.isTrue(save(data), "操作失败");
        List<DataRuleItem> items = data.getItems();
        if (DataUtil.isValuable(items)) {
            AssertUtil.isTrue(dataRuleItemService.saveBatch(data.getId(), items), "保存规则明细失败");
        }
        return data.getId();
    }

    @CacheEvict(value = AuthCacheKey.RESOURCE_RULE_MAP, key = "#data.resourceId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(DataRuleVO data) {
        handleDefaulted(data);
        AssertUtil.isTrue(updateById(data), "操作失败");
        List<DataRuleItem> items = data.getItems();
        if (DataUtil.isValuable(items)) {
            AssertUtil.isTrue(dataRuleItemService.saveBatch(data.getId(), items), "保存规则明细失败");
        }
    }

    /**
     * 处理缺省规则，一个资源下只能有一个缺省规则
     * @param data
     */
    private void handleDefaulted(DataRuleVO data) {
        if (Boolean.TRUE.equals(data.getDefaulted())) {
            boolean update = update(
                    Wrappers.<DataRule>lambdaUpdate()
                            .set(DataRule::getDefaulted, false)
                            .eq(DataRule::getResourceId, data.getResourceId())
                            .eq(DataRule::getDefaulted, true)
            );
            AssertUtil.isTrue(update, "设置缺省规则失败");
        }
    }
}
